import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.JTextComponent;


public class SolarSystem extends JApplet
{
	JLabel angmomLabel, energyLabel, eccLabel, distLabel, masslabel, auLabel, inputLabel, appletLabel;
	JTextField angmomInput, energyInput, eccentricity_out, semimajor_out;
	JSeparator separator;
	JButton StartButton, InstrButton;
	Ellipse2D.Double circle =new Ellipse2D.Double(0,0,0,0);
	JTextComponent _imaginary,_instructions;
	int appletWidth, appletHeight, angle_deg, radius;
	int control_size=15;
	boolean appStart=false;
	Dimension appletSize;
	int start=0;
	
	//Scaling factor decided according to jupiter's semi major axis
	double SCALE = 4;
	double Energy;//=-2.6503E33;
	double angular_momentum;//=2.66179E40;
	double unit_au=1.496E11;
	double G = 6.673E-11;
	
	//RMAX for all planets
	double MER_RMAX = 0.466567;
	double VEN_RMAX = 0.727916;
	double EAR_RMAX = 1.0167;
	double MAR_RMAX = 1.666342;
	double JUP_RMAX = 5.454825;
	double HAL_RMAX = 35.0126;
	
	//RMIN for all planets
	double MER_RMIN = 0.30743;
	double VEN_RMIN = 0.718084;
	double EAR_RMIN = 0.9833;
	double MAR_RMIN = 1.381658;
	double JUP_RMIN = 4.951175;
	double HAL_RMIN = 0.5874;
	
	//SMIN -  Semi-Minor axis for all planets
	double MER_SMIN = 0.3787;
	double VEN_SMIN = 0.7229;
	double EAR_SMIN = 0.9998;
	double MAR_SMIN = 1.517;
	double JUP_SMIN = 5.1969;
	double HAL_SMIN = 4.535;
	
	//SMAX -  Semi-Major axis for all planets
	double MER_SMAX = 0.387;
	double VEN_SMAX = 0.723;
	double EAR_SMAX = 1;
	double MAR_SMAX = 1.524;
	double JUP_SMAX = 5.203;
	double HAL_SMAX = 17.8;
	
	//ECC -  Eccentricities for all planets
	double MER_ECC = 0.2056;
	double VEN_ECC = 0.0068;
	double EAR_ECC = 0.0167;
	double MAR_ECC = 0.0934;
	double JUP_ECC = 0.0484;
	double HAL_ECC = 0.967;
	
	//Colors of planets
	Color MER_COL = Color.GRAY;
	Color VEN_COL = new Color(204, 149, 49);
	Color EAR_COL = Color.BLUE;
	Color MAR_COL = new Color(205, 38, 38);
	Color JUP_COL = new Color(210,105,30);
	Color HAL_COL = Color.BLACK;
	
	//Mass of all
	double SUN_MASS = 1.9891E30;
	double MER_MASS = 3.3022E23;
	double VEN_MASS = 4.8685E24;
	double EAR_MASS = 5.9742E24;
	double MAR_MASS = 6.4185E23;
	double JUP_MASS = 1.8986E27;
	double HAL_MASS = 2.2E14;
	double toy_mass=EAR_MASS;//default toy mass
	
	public void init()
	{		
		try
		{
			SwingUtilities.invokeAndWait(new Runnable()
			{	
				@Override
				public void run()
				{
					makeGUI();
				}
			});
		}catch(Exception e)
		{
			//system.out.println("Error Creating Applet");
		}
	}
	
	public void makeGUI()
	{
		/*
		String[] columnNames = {"Planet",
                "Color",
                "Angular Momentum(10^40)",
                "Energy(10^30)"};
		Object[][] data = {
			    {"Mercury", "",
			     "0.089585", "-378.54"},
			    {"Venus", "",
				  "1.8446", "-2987.3"},
				{"Earth", "",
				 "2.6618", "-2650.3"},
				{"Mars", "",
				 "0.35154", "-186.84"},
				{"Jupiter", "",
				 "1926.6", "-161880"},
				{"Halley's Comet", "",
				 "1.0538E-10", "-54.830E-10"}
			};
		*/
			
		String[] columnNames = {"",
                ""};
		Object[][] data = {
			    {"Mercury", ""},
			    {"Venus", ""},
				{"Earth", ""},
				{"Mars", ""},
				{"Jupiter", ""},
				{"Halley's Comet", ""}
			};
		
		JTable table = new JTable(data, columnNames){
			public boolean isCellEditable(int row, int column) {
				return false;
				}
			  public Component prepareRenderer(TableCellRenderer renderer,int Index_row, int Index_col) {
				  Component comp = super.prepareRenderer(renderer, Index_row, Index_col);
				  
				  if (Index_col==1) {
					  switch(Index_row){
					  case 0:
						  comp.setBackground(MER_COL);
						  break;
					  case 1:
						  comp.setBackground(VEN_COL);
						  break;
					  case 2:
						  comp.setBackground(EAR_COL);
						  break;
					  case 3:
						  comp.setBackground(MAR_COL);
						  break;
					  case 4:
						  comp.setBackground(JUP_COL);
						  break;
					  case 5:
						  comp.setBackground(HAL_COL);
						  break;
					  }
				  } 
				  else {
					  comp.setBackground(Color.white);
				  }
				  return comp;
			  }
			};
		
	    JScrollPane scrollpane = new JScrollPane(table);
	    scrollpane.setBorder(BorderFactory.createEmptyBorder());
		
		angmomLabel = new JLabel("<html>Angular Momentum (x10<sup>40</sup>)</html>", Label.LEFT);
		angmomLabel.setMinimumSize(new Dimension(175,50));
		energyLabel = new JLabel("<html>(-ve)Energy (x-10<sup>30</sup>)</html>", Label.LEFT);
		masslabel = new JLabel("Select the Mass", Label.LEFT);
		eccLabel = new JLabel("Eccentricity", Label.LEFT);
		distLabel = new JLabel("Semi Major Axis", Label.LEFT);
		appletLabel = new JLabel("Energy and Angular Momentum of Planetary Orbits", Label.LEFT);
		appletLabel.setFont(new Font("Times New Roman",Font.BOLD,20));
		auLabel = new JLabel("<html>1AU = 1.496 x 10<sup>11</sup> m.</html>", Label.LEFT);
		auLabel.setMinimumSize(new Dimension(200,50));
		inputLabel = new JLabel("INPUT (SI Units)");
		angmomInput = new JTextField("2.6503");
		energyInput = new JTextField("2661.79");
		eccentricity_out = new JTextField("---");
		semimajor_out = new JTextField("---");
		separator=new JSeparator();

		Dimension tempDim=new Dimension(appletWidth/25, appletHeight/control_size);
		StartButton = new JButton("Plot Orbit");
		InstrButton = new JButton("Instructions");
		JPanel p1 = new JPanel(new GridLayout(2, 3));
		JPanel p2 = new JPanel(new GridLayout(2, 1));
		JPanel p3 = new JPanel(new GridLayout(2, 1));
		JPanel p4 = new JPanel(new GridLayout(2, 2));
		JPanel p5 = new JPanel(new GridLayout(1, 3));
		JPanel p6 = new JPanel(new GridLayout(2, 1));
		JPanel p7 = new JPanel(new GridLayout(3, 1));
		JPanel p8 = new JPanel(new GridLayout(1, 1));
		JPanel p9 = new JPanel(new GridLayout(2, 1));
		JPanel p = new JPanel(new GridLayout(2, 1));
		JPanel kg_panel = new JPanel(new GridLayout(2, 1));
		JPanel mps_panel = new JPanel(new GridLayout(2, 1));
		JPanel deg_panel = new JPanel(new GridLayout(2, 1));
		JPanel outermost = new JPanel(new BorderLayout());
		Box button_bar = Box.createHorizontalBox();
		Box label_bar = Box.createHorizontalBox();
		Box outer2 = Box.createVerticalBox();
		
		final Choice toy_mass_select;
		toy_mass_select = new Choice();
		toy_mass_select.addItem("Mercury");
		toy_mass_select.addItem("Venus");
		toy_mass_select.addItem("Earth");
		toy_mass_select.addItem("Mars");
		toy_mass_select.addItem("Jupiter");
		toy_mass_select.addItem("Halleys");
		
		//default selection as Earth
		toy_mass_select.select("Earth");
		
		p1.add(angmomLabel);
		p1.add(energyLabel);
		p1.add(masslabel);
		p1.add(angmomInput);
		p1.add(energyInput);
		p1.add(toy_mass_select);
		
		p3.add(StartButton);
		p3.add(InstrButton);
		
		
		p6.add(eccLabel);
		p6.add(eccentricity_out);
		p6.add(distLabel);
		p6.add(semimajor_out);
		
		p7.add(new JLabel(""));
		p7.add(scrollpane);
		p7.add(new JLabel(""));
		
		p8.add(auLabel);
		
		appletSize = this.getSize();
		appletHeight = appletSize.height;
	    appletWidth = appletSize.width;
	    
	    table.getColumnModel().getColumn(0).setPreferredWidth(appletWidth/12);
	    table.getColumnModel().getColumn(1).setPreferredWidth(appletWidth/30);
	    //table.getColumnModel().getColumn(2).setPreferredWidth(appletWidth/7);
	    //table.getColumnModel().getColumn(3).setPreferredWidth(appletWidth/10);
	    
	    Dimension tempDimEast=new Dimension(appletWidth/8, appletHeight);
	    tempDim.setSize(1*appletWidth/20, appletHeight/control_size);
	    //tempDimEast.setSize(appletWidth/3.51, appletHeight/2);
	    tempDimEast.setSize(appletWidth/10, appletHeight/2);
	    p7.setPreferredSize(tempDimEast);
		p9.setPreferredSize(tempDim);
		tempDim.setSize(1*appletWidth/50, appletHeight/control_size);
		p2.setPreferredSize(tempDim);
		p2.setMaximumSize(tempDim);
		p4.setPreferredSize(tempDim);
		p4.setMaximumSize(tempDim);
		tempDim.setSize(1*appletWidth/35, appletHeight/control_size);
		p.setPreferredSize(tempDim);
		p.setMaximumSize(tempDim);		
		button_bar.add(p1);
		tempDim.setSize(appletWidth/20, appletHeight/control_size);

		button_bar.add(p2);
		button_bar.add(kg_panel);
		button_bar.add(Box.createRigidArea(tempDim));
		button_bar.add(p3);

		button_bar.add(p4);
		button_bar.add(p);
		button_bar.add(Box.createRigidArea(tempDim));
		button_bar.add(p5, Component.CENTER_ALIGNMENT);
		button_bar.add(Box.createRigidArea(tempDim));
		button_bar.add(p6);

		button_bar.add(p7);
		button_bar.add(mps_panel);
		button_bar.add(Box.createRigidArea(tempDim));
		
		button_bar.add(p8);

		button_bar.add(p9);
		button_bar.add(deg_panel);
		button_bar.add(Box.createRigidArea(tempDim));
		
		button_bar.validate();
		
		label_bar.add(inputLabel);
		label_bar.add(Box.createHorizontalGlue());

		tempDim.setSize(appletWidth/5, 0);
		label_bar.add(Box.createRigidArea(tempDim));
		label_bar.setPreferredSize(new Dimension(appletWidth, 15));
		label_bar.validate();
		tempDim.setSize(appletWidth/20, appletHeight/control_size);

		outer2.add(new JSeparator(), BorderLayout.NORTH);
		outer2.add(label_bar, BorderLayout.SOUTH);
		outer2.add(button_bar, BorderLayout.SOUTH);
		outer2.validate();
		outermost.add(appletLabel, BorderLayout.NORTH);
		outermost.add(outer2, BorderLayout.SOUTH);
		add(p7,BorderLayout.EAST);
		add(outermost,BorderLayout.SOUTH);
		add(appletLabel,BorderLayout.NORTH);
		getContentPane().setVisible(true);
		
		angular_momentum=Double.parseDouble(angmomInput.getText()) * 1E40;
		Energy=-1*Double.parseDouble(energyInput.getText()) * 1E30;
	
		StartButton.addActionListener(new ActionListener()
		{	
			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				angular_momentum=Double.parseDouble(angmomInput.getText()) * 1E40;
				Energy=-1*Double.parseDouble(energyInput.getText()) * 1E30;
				
				if(toy_mass_select.getSelectedItem().equals("Mercury")){
					toy_mass = MER_MASS;
				}
				else if(toy_mass_select.getSelectedItem().equals("Venus")){
					toy_mass = VEN_MASS;
				}
				else if(toy_mass_select.getSelectedItem().equals("Earth")){
					toy_mass = EAR_MASS;
				}
				else if(toy_mass_select.getSelectedItem().equals("Mars")){
					toy_mass = MAR_MASS;
				}
				else if(toy_mass_select.getSelectedItem().equals("Jupiter")){
					toy_mass = JUP_MASS;
				}
				else if(toy_mass_select.getSelectedItem().equals("Halleys")){
					toy_mass = HAL_MASS;
				}
				
				repaint();
				start=1;
				appStart=true;
			}
		});
		
		InstrButton.addActionListener(new ActionListener()
		{	
			@Override
			public void actionPerformed(ActionEvent arg0)
			{
				String msg = "<html><b>Aim:</b><br />"+
						"To make the toy planet's orbit overlap with the given orbits of various planets<br /> by changing the <b><i>Angular Momentum</b></i> and <b><i>Energy</b></i> of toy planet..<br /><br />"+
						"<b>Instructions to use this applet</b><ol>" +
						"<li>Input the Angular Momentum (eg: input=0.39 means 0.39 x 10<sup>40</sup>)</li>" +
						"<li>Input the Energy (eg: input=1223.3 means -1223.3 x 10<sup>30</sup>)</li>" +
						"<li>Select the Mass of the toy planet from the drop-down list.</li>" +
						"<li>Click on <b>Plot</b> to plot the orbit.</li>" +
						"<li>Eccentricity and Semi Major Axis is calculated corresponding to the given input.</li></ol><html>";
				        JLabel label = new JLabel(msg);
				        label.setFont(new Font("serif", Font.PLAIN, 14));
				JOptionPane.showMessageDialog(_instructions,label,"Instructions",JOptionPane.INFORMATION_MESSAGE);
			}
		});
		
	}
	

	public void paint(Graphics g){
		super.paintComponents(g);
		

		Graphics2D g2= (Graphics2D) g;
		
		int w= getSize().width;
		int h= getSize().height;
		
		int set_w=(int)(w*0.9);
		int set_h=(int)(h*0.9);
		g2.setClip(20,0,set_w,set_h);

		
		
		radius = (int )((h<w)?0.025*h:0.025*w);
		Ellipse2D ellipse = new Ellipse2D.Double(3*w/8-radius,h/2-radius,2*radius,2*radius);
		g2.setColor(Color.yellow);
		g2.fill(ellipse);
		
		g2.setColor(Color.red);
		g2.setStroke(new BasicStroke(2));	//to change thickness of orbits

		//draworbit(g2,rmax,rmin,b);
		draworbit(g2,MER_RMAX,MER_RMIN,MER_SMIN);
		draworbit(g2,VEN_RMAX,VEN_RMIN,VEN_SMIN);
		draworbit(g2,EAR_RMAX,EAR_RMIN,EAR_SMIN);
		draworbit(g2,MAR_RMAX,MAR_RMIN,MAR_SMIN);
		draworbit(g2,JUP_RMAX,JUP_RMIN,JUP_SMIN);
		draworbit(g2,HAL_RMAX,HAL_RMIN,HAL_SMIN);
		
		//drawplanet(g2,a,ecc,angle in degree,radius,color)
		drawplanet(g2, MER_SMAX, MER_ECC, 90, (h<w)?0.009*h:0.009*w, MER_COL);
		drawplanet(g2, VEN_SMAX, VEN_ECC, -60, (h<w)?0.015*h:0.015*w, VEN_COL);
		drawplanet(g2, EAR_SMAX, EAR_ECC, 150, (h<w)?0.015*h:0.015*w, EAR_COL);
		drawplanet(g2, MAR_SMAX, MAR_ECC, 270, (h<w)?0.01*h:0.01*w, MAR_COL);
		drawplanet(g2, JUP_SMAX, JUP_ECC, 0, (h<w)?0.02*h:0.02*w, JUP_COL);
		drawplanet(g2, HAL_SMAX, HAL_ECC, 120, (h<w)?0.015*h:0.015*w, HAL_COL);
		
		
		double red_mass= (SUN_MASS*toy_mass)/(SUN_MASS+toy_mass);
		double c = G*SUN_MASS*toy_mass;
		//System.out.println("red mass: "+red_mass);

		//find semi major axis
		double toy_semimajor=-c/(2*Energy);
		toy_semimajor=toy_semimajor/unit_au;
		double toy_ecc=Math.sqrt(1+(2*Energy*(angular_momentum*angular_momentum)/(red_mass*c*c)));
		double toy_semiminor = toy_semimajor*Math.sqrt((1-toy_ecc*toy_ecc));
		eccentricity_out.setText(""+(double)Math.round(toy_ecc * 1000000) / 1000000);
		semimajor_out.setText(""+(double)Math.round(toy_semimajor * 1000000) / 1000000+" AU");
		
		if(Double.isNaN(toy_ecc)){
			//System.out.println("\neccentricity is imaginary :P");
			eccentricity_out.setText("---");
			JOptionPane.showMessageDialog(_imaginary,"The given Energy and Angular Momentum result in an imaginary eccentricity.","Error",JOptionPane.ERROR_MESSAGE);	
		}
			
		
		double toy_rmax=toy_semimajor*(1-toy_ecc*toy_ecc)/(1-toy_ecc);
		double toy_rmin=toy_semimajor*(1-toy_ecc*toy_ecc)/(1+toy_ecc);
		//System.out.println("rmax: "+toy_rmax);
		//System.out.println("rmin: "+toy_rmin);
		g2.setColor(Color.BLACK);
		draworbit(g2,toy_rmax,toy_rmin,toy_semiminor);
		
	}

	private void draworbit(Graphics2D g2,double RMAX, double RMIN, double SM) {
		int w= getSize().width;
		int h= getSize().height;
		
		RMIN = (w*RMIN)/(SCALE*4);
		RMAX = (w*RMAX)/(SCALE*4);
		SM = (w*SM)/(SCALE*4);
		
		Ellipse2D ellipse = new Ellipse2D.Double(3*w/8-RMIN,h/2-SM,RMIN+RMAX,2*SM);
		g2.draw(ellipse);
	}
	
	private void drawplanet(Graphics2D g2, double SMAX, double ECC, int angle_deg, double radius, Color _color) {
		int w= getSize().width;
		int h= getSize().height;
		double angle_rad = angle_deg * Math.PI/180;
		double r = ( w/(SCALE*4) ) * SMAX * (1 - ECC*ECC) / (1 + ECC*Math.cos(angle_rad) );
		double x = -1*r * Math.cos(angle_rad);
		double y = r * Math.sin(angle_rad);
		x=x+3*w/8;
		y=y+h/2;
		
		Ellipse2D ellipse = new Ellipse2D.Double(x-radius,y-radius,2*radius,2*radius);
		g2.setColor(_color);
		g2.fill(ellipse);
		
	}
	
}